﻿using System.Collections.Generic;
using System.ComponentModel;

namespace Faz.SideWinderSC.Client.ViewModel
{
    /// <summary>
    /// Base class for the view-model implementation.
    /// </summary>
    public abstract class AbstractViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// The stored values.
        /// </summary>
        private readonly IDictionary<string, object> values;

        /// <summary>
        /// Occurs when a property is updated.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Initializes a new instance of the <see cref="AbstractViewModel"/> class.
        /// </summary>
        protected AbstractViewModel()
        {
            this.values = new Dictionary<string, object>();
        }

        /// <summary>
        /// Retrieves a named value.
        /// </summary>
        /// <typeparam name="T">The type of the value to retrieve.</typeparam>
        /// <param name="propertyName">The name of the property.</param>
        /// <returns>
        /// The value identified by <paramref name="propertyName"/>;
        /// or the default value of the type <typeparamref name="T"/>.
        /// </returns>
        /// <seealso cref="AbstractViewModel.SetValue{T}"/>
        protected T GetValue<T>(string propertyName)
        {
            if (this.values.ContainsKey(propertyName))
            {
                return (T)this.values[propertyName];
            }
            else
            {
                return default(T);
            }
        }

        /// <summary>
        /// Defines a named value.
        /// </summary>
        /// <typeparam name="T">The type of the defined value.</typeparam>
        /// <param name="propertyName">The name of the property.</param>
        /// <param name="value">The value of the property.</param>
        /// <remarks>
        /// Raises the <see cref="AbstractViewModel.PropertyChanged"/> event if the
        /// value has changed.
        /// </remarks>
        /// <seealso cref="AbstractViewModel.GetValue{T}"/>
        protected void SetValue<T>(string propertyName, T value)
        {
            if (!object.Equals(this.GetValue<T>(propertyName), value))
            {
                this.values[propertyName] = value;
                this.OnPropertyChanged(propertyName);
            }
        }

        /// <summary>
        /// Raises the <see cref="AbstractViewModel.PropertyChanged"/>.
        /// </summary>
        /// <param name="propertyName">The name of the updated property.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
